const fs = require('fs')
const path = require('path')
const vm = require('vm')
/**
 * 先要将文件转换为绝对路径
 * 判断文件是否存在，不存在补充文件后缀名继续查找
 * 找到文件路径后，查找是否模块已经被加载，从cache中取出模块
 * 未找到模块，就重新创建一个模块，根据文件后缀名调用加载函数，将结果加入到module的exports中
 */

class Module {
    constructor(id) {
        this.id = id
        this.exports = {}
    }

    load() {
        const extname = path.extname(this.id)
        const value  = Module._extensions[extname](this)
    }

    static _resolveFilename(filename) {
        // 文件路径转换为绝对路径
        const absPath = path.resolve(__dirname, filename)

        if (fs.existsSync(absPath)) {
            return absPath
        } else {
            const suffix = Object.keys(Module._extensions)
            for (let index = 0; index < suffix.length; index++) {
                const path = absPath + suffix[index];
                if (fs.existsSync(path)) {
                    return path
                }
            }
        }
        throw new Error(`${filename} is not exists`)
    }

    static _extensions = {
        '.js': (module) => {
            // 首先读取文件
            let content = fs.readFileSync(module.id, 'utf-8')
            content = Module._wrapper[0] + content + Module._wrapper[1]
            const compileFn = vm.runInThisContext(content)
            const exports = module.exports
            const filename = module.id
            const dirname = path.dirname(module.id)
            compileFn.call(exports, exports, myRequire, module, filename, dirname)
        },
        '.json': (module) => {
            const content = fs.readFileSync(module.id, 'utf-8')
            module.exports = JSON.parse(content)
        }
    }

    static _cacheModules = {}

    static _wrapper = ['(function(exports, require, module, __filename, __dirname) {', '})']
}

function myRequire(filename) {
    const mPath = Module._resolveFilename(filename)
    // 优先缓存
    const cacheModule = Module._cacheModules[mPath]
    if (cacheModule) return cacheModule
    // 创建一个新的模块
    const newModule = new Module(mPath)
    // 模块加载
    newModule.load()
    // 将模块加入缓存
    Module._cacheModules[mPath] = newModule
    // 返回导入数据
    return newModule.exports
}


const aModule = myRequire('./test/example')
const bModule = myRequire('./test/aa')
console.log(aModule.a)
console.log(bModule)